﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RSCore.Helper.Collection
{

    /// <summary>
    /// This collection allows to add new elements and insure that they
    /// are not already into the collection.
    /// </summary>
    sealed public class UnicityList<T>
    {

        #region Variables

        protected T[] _elements;
        protected int _count;
        protected int _size;

        #endregion

        #region Constructor

        public UnicityList()
        {
            _count = 0;
            _size = 0;
            _elements = null;
        }

        public UnicityList(int reserve)
        {
            _count = 0;
            _size = 0;
            _elements = null;
            Reserve(reserve);
        }

        private void Reserve(int s)
        {
            int i;
            T[] newset;
            if (s <= _size) return;
            else
            {
                if (s == 0) s = 1;
                newset = new T[s];
                for (i = 0; i < _size; i++) newset[i] = _elements[i];
                _size = s;
                _elements = newset;
            }
        }

        #endregion

        #region Properties

        public int Count
        {
            get
            {
                return _count;
            }
        }

        public T this[int i]
        {
            get
            {
                return _elements[i];
            }
            set
            {
                if (i >= _count)
                    _count = i + 1;
                _elements[i] = value;
            }
        }

        #endregion

        #region Clear

        public void Clear()
        {
            _count = 0;
            _size = 0;
            _elements = null;
        }

        #endregion

        #region Add...

        public int Add(T x)
        {
            for (int i = 0; i < _count; i++)
                if (_elements[i].Equals(x))
                    return i;

            push_back(x);
            _count++;
            return _count - 1;
        }

        public int AddWithoutCheck(T x)
        {
            push_back(x);
            _count++;

            return _count - 1;
        }

        private void push_back(T x)
        {
            int ns, i;
            T[] newset;

            if (_count < _size)
                _elements[_count] = x;
            else
            {
                if (_size == 0)
                    ns = 1;

                // Grow by ten percent, but at least 1
                else ns = _size * 110 / 100 + 1;
                newset = new T[ns];
                for (i = 0; i < _size; i++)
                    newset[i] = _elements[i];
                _size = ns;
                _elements = newset;
                _elements[_count] = x;
            }
        }

        #endregion

        #region Remove

        public void Remove(T x)
        {
            for (int i = 0; i < _count; i++)
                if (_elements[i].Equals(x))
                {
                    _elements[i] = _elements[_count - 1];
                    pop_back();
                    _count--;
                    return;
                }
        }

        public void Remove(int i)
        {
            if (i < 0)
                return;
            if (i >= _count)
                return;

            _elements[i] = _elements[_count - 1];

            pop_back();

            _count--;
        }

        private void pop_back()
        {
        }

        #endregion

        #region IndexOf

        public int IndexOf(T x)
        {
            for (int i = 0; i < _count; i++)
                if (_elements[i].Equals(x))
                    return i;

            return -1;
        }

        #endregion

        #region Contains

        public bool Contains(T x)
        {
            int i = IndexOf(x);
            if (i != -1)
                return true;

            return false;
        }

        #endregion

        #region Match

        /// <summary>
        /// Returns the element in the list that correspond to this element.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public T Match(T x)
        {
            int i = IndexOf(x);
            if (i != -1)
                return _elements[i];

            return default(T);
        }

        #endregion

        #region Clone

        public UnicityList<T> Clone()
        {
            UnicityList<T> f = new UnicityList<T>();

            f._elements = (T[])_elements.Clone();
            f._count = _count;
            f._size = _size;

            return f;
        }

        #endregion

    }

}
